package com.rd.animation.type;

import com.rd.animation.controller.ValueController;
import com.rd.animation.data.type.ThinWormAnimationValue;
import com.rd.utils.AnimatorUtils;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;

public class ThinWormAnimation extends WormAnimation {
    private ThinWormAnimationValue value;

    public ThinWormAnimation(ValueController.UpdateListener listener) {
        super(listener);
        value = new ThinWormAnimationValue();
    }

    @Override
    public ThinWormAnimation duration(long duration) {
        super.duration(duration);
        return this;
    }

    @Override
    public WormAnimation with(int coordinateStart, int coordinateEnd, int radius, boolean isRightSide) {
        if (hasChanges(coordinateStart, coordinateEnd, radius, isRightSide)) {
            animator = createAnimator();

            this.coordinateStart = coordinateStart;
            this.coordinateEnd = coordinateEnd;

            this.radius = radius;
            this.isRightSide = isRightSide;

            int height = radius * 2;
            rectLeftEdge = coordinateStart - radius;
            rectRightEdge = coordinateStart + radius;

            value.setRectStart(rectLeftEdge);
            value.setRectEnd(rectRightEdge);
            value.setHeight(height);

            RectValues rec = createRectValues(isRightSide);
            long sizeDuration = (long) (animationDuration * 0.8);
            long reverseDelay = (long) (animationDuration * 0.2);

            long heightDuration = (long) (animationDuration * 0.5);
            long reverseHeightDelay = (long) (animationDuration * 0.5);

            ValueAnimator straightAnimator = createWormAnimator(rec.fromX, rec.toX, sizeDuration, false, value);
            ValueAnimator reverseAnimator =
                    createWormAnimator(rec.reverseFromX, rec.reverseToX, sizeDuration, true, value);
            reverseAnimator.setDelay(reverseDelay);

            ValueAnimator straightHeightAnimator = createHeightAnimator(height, radius, heightDuration);
            ValueAnimator reverseHeightAnimator = createHeightAnimator(radius, height, heightDuration);
            reverseHeightAnimator.setDelay(reverseHeightDelay);
            animator.runParallel(straightAnimator, reverseAnimator, straightHeightAnimator, reverseHeightAnimator);
        }
        return this;
    }

    private ValueAnimator createHeightAnimator(int fromHeight, int toHeight, long duration) {
        ValueAnimator anim = new ValueAnimator();
        anim.setCurveType(Animator.CurveType.ACCELERATE_DECELERATE);
        anim.setDuration(duration);
        anim.setInnerListener(
                new InnerValueUpdateListener() {
                    @Override
                    public void onUpdate(AnimatorValue animatorValue, float f) {
                        height = AnimatorUtils.getIntValue(fromHeight, toHeight, f);
                    }
                });
        anim.setValueUpdateListener(
                new AnimatorValue.ValueUpdateListener() {
                    @Override
                    public void onUpdate(AnimatorValue animatorValue, float v) {
                        anim.onUpdate(animatorValue, v);
                        onAnimateUpdated(animatorValue);
                    }
                });

        return anim;
    }

    int height;

    private void onAnimateUpdated(AnimatorValue animation) {
        value.setHeight(height);

        if (listener != null) {
            listener.onValueUpdated(value);
        }
    }

    @Override
    public ThinWormAnimation progress(float progress) {
        if (animator != null) {
            long progressDuration = (long) (progress * animationDuration);
            int size = animator.getAnimatorsAt(0).size();

            for (int i = 0; i < size; i++) {
                AnimatorValue anim = (AnimatorValue) animator.getAnimatorsAt(0).get(i);

                long setDuration = progressDuration - anim.getDelay();
                long duration = anim.getDuration();

                if (setDuration > duration) {
                    setDuration = duration;

                } else if (setDuration < 0) {
                    setDuration = 0;
                }

                if (i == size - 1 && setDuration <= 0) {
                    continue;
                }
            }
        }

        return this;
    }
}
